home *** CD-ROM | disk | FTP | other *** search
/ Programming an RTS Game with Direct3D / Programming an RTS Game with Direct3D.iso / Examples / Chapter 4 / Example 4.8 / terrain.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2006-07-01  |  7.1 KB  |  276 lines

  1. #include "terrain.h"
  2.  
  3. const DWORD TERRAINVertex::FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX2;
  4.  
  5. //////////////////////////////////////////////////////////////////////////////////////////
  6. //                                    PATCH                                                //
  7. //////////////////////////////////////////////////////////////////////////////////////////
  8.  
  9. PATCH::PATCH()
  10. {
  11.     m_pDevice = NULL;
  12.     m_pMesh = NULL;
  13. }
  14. PATCH::~PATCH()
  15. {
  16.     Release();
  17. }
  18.  
  19. void PATCH::Release()
  20. {
  21.     if(m_pMesh != NULL)
  22.         m_pMesh->Release();
  23.     m_pMesh = NULL;
  24. }
  25.  
  26. HRESULT PATCH::CreateMesh(HEIGHTMAP &hm, RECT source, IDirect3DDevice9* Dev)
  27. {
  28.     if(m_pMesh != NULL)
  29.     {
  30.         m_pMesh->Release();
  31.         m_pMesh = NULL;
  32.     }
  33.  
  34.     try
  35.     {
  36.         m_pDevice = Dev;
  37.  
  38.         int width = source.right - source.left;
  39.         int height = source.bottom - source.top;
  40.         int nrVert = (width + 1) * (height + 1);
  41.         int nrTri = width * height * 2;
  42.  
  43.         if(FAILED(D3DXCreateMeshFVF(nrTri, nrVert, D3DXMESH_MANAGED, TERRAINVertex::FVF, m_pDevice, &m_pMesh)))
  44.         {
  45.             debug.Print("Couldn't create mesh for PATCH");
  46.             return E_FAIL;
  47.         }
  48.  
  49.         //Create vertices
  50.         TERRAINVertex* ver = 0;
  51.         m_pMesh->LockVertexBuffer(0,(void**)&ver);
  52.         for(int z=source.top, z0 = 0;z<=source.bottom;z++, z0++)
  53.             for(int x=source.left, x0 = 0;x<=source.right;x++, x0++)
  54.             {
  55.                 D3DXVECTOR3 pos = D3DXVECTOR3(x, hm.m_pHeightMap[x + z * hm.m_size.x], -z);
  56.                 D3DXVECTOR2 alphaUV = D3DXVECTOR2(x / (float)hm.m_size.x, z / (float)hm.m_size.y);        //Alpha UV
  57.                 D3DXVECTOR2 colorUV = alphaUV * 8.0f;                                                    //Color UV
  58.                 ver[z0 * (width + 1) + x0] = TERRAINVertex(pos, alphaUV, colorUV);
  59.             }
  60.         m_pMesh->UnlockVertexBuffer();
  61.  
  62.         //Calculate Indices
  63.         WORD* ind = 0;
  64.         m_pMesh->LockIndexBuffer(0,(void**)&ind);    
  65.         int index = 0;
  66.  
  67.         for(int z=source.top, z0 = 0;z<source.bottom;z++, z0++)
  68.             for(int x=source.left, x0 = 0;x<source.right;x++, x0++)
  69.             {
  70.                 //Triangle 1
  71.                 ind[index++] =   z0   * (width + 1) + x0;
  72.                 ind[index++] =   z0   * (width + 1) + x0 + 1;
  73.                 ind[index++] = (z0+1) * (width + 1) + x0;        
  74.  
  75.                 //Triangle 2
  76.                 ind[index++] = (z0+1) * (width + 1) + x0;
  77.                 ind[index++] =   z0   * (width + 1) + x0 + 1;
  78.                 ind[index++] = (z0+1) * (width + 1) + x0 + 1;
  79.             }
  80.  
  81.         m_pMesh->UnlockIndexBuffer();
  82.  
  83.         //Set Attributes
  84.         DWORD *att = 0, a = 0;
  85.         m_pMesh->LockAttributeBuffer(0,&att);
  86.         memset(att, 0, sizeof(DWORD)*nrTri);
  87.         m_pMesh->UnlockAttributeBuffer();
  88.  
  89.         //Compute normals
  90.         D3DXComputeNormals(m_pMesh, NULL);
  91.     }
  92.     catch(...)
  93.     {
  94.         debug.Print("Error in PATCH::CreateMesh()");
  95.         return E_FAIL;
  96.     }
  97.  
  98.     return S_OK;
  99. }
  100.  
  101. void PATCH::Render()
  102. {
  103.     //Draw mesh
  104.     if(m_pMesh != NULL)
  105.         m_pMesh->DrawSubset(0);
  106. }
  107.  
  108. //////////////////////////////////////////////////////////////////////////////////////////
  109. //                                    TERRAIN                                                //
  110. //////////////////////////////////////////////////////////////////////////////////////////
  111.  
  112. TERRAIN::TERRAIN()
  113. {
  114.     m_pDevice = NULL;
  115. }
  116.  
  117. void TERRAIN::Init(IDirect3DDevice9* Dev, INTPOINT _size)
  118. {
  119.     m_pDevice = Dev;
  120.     m_size = _size;
  121.     m_pHeightMap = NULL;
  122.  
  123.     //Load textures
  124.     IDirect3DTexture9* grass = NULL, *mount = NULL, *snow = NULL;
  125.     if(FAILED(D3DXCreateTextureFromFile(Dev, "textures/grass.jpg", &grass)))debug.Print("Could not load grass.jpg");
  126.     if(FAILED(D3DXCreateTextureFromFile(Dev, "textures/mountain.jpg", &mount)))debug.Print("Could not load mountain.jpg");
  127.     if(FAILED(D3DXCreateTextureFromFile(Dev, "textures/snow.jpg", &snow)))debug.Print("Could not load snow.jpg");
  128.     m_diffuseMaps.push_back(grass);
  129.     m_diffuseMaps.push_back(mount);
  130.     m_diffuseMaps.push_back(snow);
  131.     m_pAlphaMap = NULL;
  132.  
  133.     //Load pixelshader
  134.     m_terrainPS.Init(Dev, "Shaders/terrain.ps", PIXEL_SHADER);
  135.  
  136.     //Create white material    
  137.     m_mtrl.Ambient = m_mtrl.Specular = m_mtrl.Diffuse  = D3DXCOLOR(0.5f, 0.5f, 0.5f, 1.0f);
  138.     m_mtrl.Emissive = D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f);
  139.  
  140.     GenerateRandomTerrain(3);
  141. }
  142.  
  143. void TERRAIN::Release()
  144. {
  145.     for(int i=0;i<m_patches.size();i++)
  146.         if(m_patches[i] != NULL)
  147.             m_patches[i]->Release();
  148.  
  149.     m_patches.clear();
  150.  
  151.     if(m_pHeightMap != NULL)
  152.     {
  153.         m_pHeightMap->Release();
  154.         delete m_pHeightMap;
  155.         m_pHeightMap = NULL;
  156.     }
  157. }
  158.  
  159. void TERRAIN::GenerateRandomTerrain(int numPatches)
  160. {
  161.     try
  162.     {
  163.         Release();
  164.  
  165.         //Create two heightmaps and multiply them
  166.         m_pHeightMap = new HEIGHTMAP(m_size, 20.0f);
  167.         HEIGHTMAP hm2(m_size, 20.0f);
  168.  
  169.         m_pHeightMap->CreateRandomHeightMap(rand()%2000, 2.0f, 0.7f, 8);
  170.         hm2.CreateRandomHeightMap(rand()%2000, 2.5f, 0.8f, 3);
  171.  
  172.         hm2.Cap(hm2.m_fMaxHeight * 0.4f);
  173.  
  174.         *m_pHeightMap *= hm2;
  175.         hm2.Release();
  176.  
  177.         CreatePatches(numPatches);
  178.         CalculateAlphaMaps();
  179.     }
  180.     catch(...)
  181.     {
  182.         debug.Print("Error in TERRAIN::GenerateRandomTerrain()");
  183.     }
  184. }
  185.  
  186. void TERRAIN::CreatePatches(int numPatches)
  187. {
  188.     try
  189.     {
  190.         //Clear any old m_patches
  191.         for(int i=0;i<m_patches.size();i++)
  192.             if(m_patches[i] != NULL)
  193.                 m_patches[i]->Release();
  194.         m_patches.clear();
  195.  
  196.         if(m_pHeightMap == NULL)return;
  197.  
  198.         //Create new m_patches
  199.         for(int y=0;y<numPatches;y++)
  200.             for(int x=0;x<numPatches;x++)
  201.             {
  202.                 RECT r = {x * (m_size.x - 1) / (float)numPatches, 
  203.                           y * (m_size.y - 1) / (float)numPatches, 
  204.                         (x+1) * (m_size.x - 1) / (float)numPatches,
  205.                         (y+1) * (m_size.y - 1) / (float)numPatches};
  206.                         
  207.                 PATCH *p = new PATCH();
  208.                 p->CreateMesh(*m_pHeightMap, r, m_pDevice);
  209.                 m_patches.push_back(p);
  210.             }
  211.     }
  212.     catch(...)
  213.     {
  214.         debug.Print("Error in TERRAIN::CreatePatches()");
  215.     }
  216. }
  217.  
  218. void TERRAIN::CalculateAlphaMaps()
  219. {
  220.     //Clear old alpha maps
  221.     if(m_pAlphaMap != NULL)
  222.         m_pAlphaMap->Release();
  223.  
  224.     //height ranges...
  225.     float min_range[] = {0.0f, 1.0f, 15.0f};
  226.     float max_range[] = {2.0f, 16.0f, 21.0f};
  227.  
  228.     D3DXCreateTexture(m_pDevice, 128, 128, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pAlphaMap);
  229.  
  230.     //Lock the texture
  231.     D3DLOCKED_RECT sRect;
  232.     m_pAlphaMap->LockRect(0, &sRect, NULL, NULL);
  233.     BYTE *bytes = (BYTE*)sRect.pBits;
  234.     memset(bytes, 0, 128*sRect.Pitch);        //Clear texture to black
  235.  
  236.     for(int i=0;i<m_diffuseMaps.size();i++)
  237.         for(int y=0;y<sRect.Pitch / 4;y++)
  238.             for(int x=0;x<sRect.Pitch / 4;x++)
  239.             {
  240.                 int hm_x = m_pHeightMap->m_size.x * (x / (float)(sRect.Pitch / 4.0f));
  241.                 int hm_y = m_pHeightMap->m_size.y * (y / (float)(sRect.Pitch / 4.0f));
  242.                 float height = m_pHeightMap->m_pHeightMap[hm_x + hm_y * m_pHeightMap->m_size.x];
  243.  
  244.                 BYTE *b = bytes + y * sRect.Pitch + x * 4 + i;
  245.                 if(height >= min_range[i] && height <= max_range[i])
  246.                     *b = 255;
  247.                 else *b = 0;
  248.             }
  249.  
  250.     //Unlock the texture
  251.     m_pAlphaMap->UnlockRect(0);
  252.     
  253.     //D3DXSaveTextureToFile("alpha.bmp", D3DXIFF_BMP, m_pAlphaMap, NULL);
  254. }
  255.  
  256. void TERRAIN::Render()
  257. {
  258.     //Set render states        
  259.     m_pDevice->SetRenderState(D3DRS_LIGHTING, false);
  260.     m_pDevice->SetRenderState(D3DRS_ZWRITEENABLE, true);    
  261.     
  262.     //Set Textures
  263.     m_pDevice->SetTexture(0, m_pAlphaMap);
  264.     m_pDevice->SetTexture(1, m_diffuseMaps[0]);        //Grass
  265.     m_pDevice->SetTexture(2, m_diffuseMaps[1]);        //Mountain
  266.     m_pDevice->SetTexture(3, m_diffuseMaps[2]);        //Snow
  267.     
  268.     m_pDevice->SetMaterial(&m_mtrl);
  269.  
  270.     m_terrainPS.Begin();
  271.         
  272.     for(int p=0;p<m_patches.size();p++)
  273.         m_patches[p]->Render();
  274.  
  275.     m_terrainPS.End();    
  276. }